package com.game.modular.game.playerAssets.service.base;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.game.comment.exection.ServiceException;
import lombok.extern.slf4j.Slf4j;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.game.modular.game.playerAssets.mapper.PlayerSkillMapper;
import com.game.modular.game.playerAssets.domain.PlayerSkill;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;

/**
 * 基础服务-游戏账户技能数据
 *
 * @author cxy
 * @since 2024-09-12 16:09:34
 */
@Slf4j
@Service
@Validated
public class PlayerSkillBaseServiceImpl extends ServiceImpl<PlayerSkillMapper, PlayerSkill> {
    private static final String cacheKey = "player:%d:skill";
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    private ValueOperations<Object, PlayerSkill> valueOperations;
    @Resource
    private HashOperations<Object, Object, PlayerSkill> hashOperations;
    @Resource
    private PlayerSkillMapper playerSkillMapper;


    ///////////////////////////////////////////////////////////////////////////////////////////////////////////  基础查询
    public List<PlayerSkill> list(Long playerId) {
        List<PlayerSkill> playerSkills = listCache(playerId);
        if (playerSkills.isEmpty()) {
            List<PlayerSkill> accountSkills =
                    super.list(new LambdaQueryWrapper<PlayerSkill>()
                            .eq(PlayerSkill::getUid, playerId));
            if (!accountSkills.isEmpty()) {
                savaCache(playerId, listToMap(accountSkills));
            }
        }
        return new ArrayList<>(playerSkills);
    }

    public PlayerSkill selectByCoreSkillId(
            @NotNull(message = "玩家id不能为空") Long playerId,
            @NotNull(message = "coreSkillId不能为空") Long coreSkillId
    ) {
        PlayerSkill playerSkill = list(playerId).stream()
                .filter(accountSkill -> accountSkill.getCoreSkillId().equals(coreSkillId))
                .findFirst().orElse(null);

        if (playerSkill == null) {
            playerSkill = super.getOne(new LambdaQueryWrapper<PlayerSkill>()
                    .eq(PlayerSkill::getUid, playerId)
                    .eq(PlayerSkill::getCoreSkillId, coreSkillId)
            );
            if (playerSkill == null) {
                return null;
            }
            savaCache(playerSkill);
        }
        return playerSkill;
    }

    public PlayerSkill selectByCoreSkillStarId(
            @NotNull(message = "玩家id不能为空") Long playerId,
            @NotNull(message = "coreSkillStarId不能为空") Long coreSkillStarId
    ) {
        PlayerSkill playerSkill = list(playerId).stream()
                .filter(accountSkill -> accountSkill.getCoreSkillStarId().equals(coreSkillStarId))
                .findFirst().orElse(null);

        if (playerSkill == null) {
            PlayerSkill select = PlayerSkill.builder().uid(playerId).coreSkillStarId(coreSkillStarId).build();
            playerSkill = select(select);
            if (playerSkill == null) {
                return null;
            }
            savaCache(playerSkill);
        }
        return playerSkill;
    }

    public PlayerSkill select(PlayerSkill select) {
        LambdaQueryWrapper<PlayerSkill> playerSkillLambdaQueryWrapper = new LambdaQueryWrapper<>(select);
        return super.getOne(playerSkillLambdaQueryWrapper);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////    转换
    public Map<String, PlayerSkill> listToMap(List<PlayerSkill> list) {
        return list.stream().collect(Collectors.toMap(
                k -> k.getCoreSkillId().toString(),//@todo 修改keyValue2
                v -> v
        ));
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////  更新插入
    @Override
    public boolean updateById(PlayerSkill entity) {
        boolean b = super.updateById(entity);
        PlayerSkill byId = super.getById(entity.getId());
        savaCache(byId);
        return b;
    }

    @Override
    public boolean save(PlayerSkill entity) {
        boolean save = super.save(entity);
        savaCache(entity);
        return save;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////  缓存部分
    public void savaCache(Long keyValue1, Map<String, PlayerSkill> map) {
        String key1 = String.format(cacheKey, keyValue1);
        hashOperations.putAll(key1, map);
        redisTemplate.expire(key1, 60, TimeUnit.MINUTES);
    }

    public void savaCache(@NotNull PlayerSkill entity) {
        String key1 = String.format(cacheKey, entity.getUid());
        String key2 = entity.getCoreSkillId().toString();
        hashOperations.put(key1, key2, entity);
        redisTemplate.expire(key1, 60, TimeUnit.MINUTES);
    }

    public PlayerSkill selectCache(
            @NotNull(message = "uid不能为空") Long uid,
            @NotNull(message = "coreSkillId不能为空") Long coreSkillId
    ) {
        String key1 = String.format(cacheKey, uid);
        String key2 = coreSkillId.toString();
        redisTemplate.expire(key1, 60, TimeUnit.MINUTES);
        return hashOperations.get(key1, key2);
    }

    public List<PlayerSkill> listCache(
            @NotNull(message = "uid不能为空") Long uid
    ) {
        String key1 = String.format(cacheKey, uid);
        redisTemplate.expire(key1, 60, TimeUnit.MINUTES);
        return new ArrayList<>(hashOperations.entries(key1).values());
    }

    public void removeCache(PlayerSkill entity) {
        String key1 = String.format(cacheKey, entity.getUid());
        String key2 = entity.getCoreSkillId().toString();
        hashOperations.delete(key1, key2);
    }
}
